﻿namespace Holoville.HOTween
{
    using Holoville.HOTween.Core;
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using UnityEngine;

    public class Sequence : ABSTweenComponent
    {
        private bool hasCallbacks;
        private List<HOTSeqItem> items;
        private float prevElapsed;
        private int prevIncrementalCompletedLoops;

        public Sequence() : this(null)
        {
        }

        public Sequence(SequenceParms p_parms)
        {
            if (p_parms != null)
            {
                p_parms.InitializeSequence(this);
            }
            base._isPaused = true;
            Holoville.HOTween.HOTween.AddSequence(this);
        }

        public float Append(IHOTweenComponent p_twMember)
        {
            return this.Append(p_twMember, 0f);
        }

        private float Append(IHOTweenComponent p_twMember, float p_duration)
        {
            if (this.items == null)
            {
                return ((p_twMember == null) ? this.Insert(0f, null, p_duration) : this.Insert(0f, p_twMember));
            }
            if (p_twMember != null)
            {
                Holoville.HOTween.HOTween.RemoveFromTweens(p_twMember);
                ((ABSTweenComponent) p_twMember).contSequence = this;
                CheckSpeedBasedTween(p_twMember);
            }
            HOTSeqItem item = (p_twMember == null) ? new HOTSeqItem(base._duration, p_duration) : new HOTSeqItem(base._duration, p_twMember as ABSTweenComponent);
            this.items.Add(item);
            base._duration += item.duration;
            base.SetFullDuration();
            base._isEmpty = false;
            return base._duration;
        }

        public void AppendCallback(TweenDelegate.TweenCallback p_callback)
        {
            this.InsertCallback(base._duration, p_callback);
        }

        public void AppendCallback(TweenDelegate.TweenCallbackWParms p_callback, params object[] p_callbackParms)
        {
            this.InsertCallback(base._duration, p_callback, p_callbackParms);
        }

        public void AppendCallback(GameObject p_sendMessageTarget, string p_methodName, object p_value, SendMessageOptions p_options = 0)
        {
            this.InsertCallback(base._duration, p_sendMessageTarget, p_methodName, p_value, p_options);
        }

        public float AppendInterval(float p_duration)
        {
            return this.Append(null, p_duration);
        }

        private static void CheckSpeedBasedTween(IHOTweenComponent p_twMember)
        {
            Tweener tweener = p_twMember as Tweener;
            if ((tweener != null) && tweener._speedBased)
            {
                tweener.ForceSetSpeedBasedDuration();
            }
        }

        public void Clear(SequenceParms p_parms = null)
        {
            this.Kill(false);
            this.Reset();
            this.hasCallbacks = false;
            this.prevIncrementalCompletedLoops = this.prevIncrementalCompletedLoops = 0;
            base._destroyed = false;
            if (p_parms != null)
            {
                p_parms.InitializeSequence(this);
            }
            base._isPaused = true;
        }

        internal override void Complete(bool p_autoRemoveFromHOTween)
        {
            if (base._enabled && ((this.items != null) && (base._loops >= 0)))
            {
                base._fullElapsed = base._fullDuration;
                base.Update(0f, true);
                if (base._autoKillOnComplete)
                {
                    this.Kill(p_autoRemoveFromHOTween);
                }
            }
        }

        internal override void FillPluginsList(List<ABSTweenPlugin> p_plugs)
        {
            if (this.items != null)
            {
                int count = this.items.Count;
                for (int i = 0; i < count; i++)
                {
                    HOTSeqItem item = this.items[i];
                    if (item.twMember != null)
                    {
                        Sequence twMember = item.twMember as Sequence;
                        if (twMember != null)
                        {
                            twMember.FillPluginsList(p_plugs);
                        }
                        else
                        {
                            item.twMember.FillPluginsList(p_plugs);
                        }
                    }
                }
            }
        }

        public List<Tweener> GetTweenersByTarget(object p_target)
        {
            List<Tweener> list = new List<Tweener>();
            int count = this.items.Count;
            for (int i = 0; i < count; i++)
            {
                HOTSeqItem item = this.items[i];
                if (item.seqItemType == SeqItemType.Tween)
                {
                    Tweener twMember = item.twMember as Tweener;
                    if (twMember != null)
                    {
                        if (twMember.target == p_target)
                        {
                            list.Add(twMember);
                        }
                    }
                    else
                    {
                        list.AddRange(((Sequence) item.twMember).GetTweenersByTarget(p_target));
                    }
                }
            }
            return list;
        }

        internal override List<IHOTweenComponent> GetTweensById(string p_id)
        {
            List<IHOTweenComponent> list = new List<IHOTweenComponent>();
            if (this.id == p_id)
            {
                list.Add(this);
            }
            int count = this.items.Count;
            for (int i = 0; i < count; i++)
            {
                HOTSeqItem item = this.items[i];
                if (item.seqItemType == SeqItemType.Tween)
                {
                    list.AddRange(item.twMember.GetTweensById(p_id));
                }
            }
            return list;
        }

        internal override List<IHOTweenComponent> GetTweensByIntId(int p_intId)
        {
            List<IHOTweenComponent> list = new List<IHOTweenComponent>();
            if (this.intId == p_intId)
            {
                list.Add(this);
            }
            int count = this.items.Count;
            for (int i = 0; i < count; i++)
            {
                HOTSeqItem item = this.items[i];
                if (item.seqItemType == SeqItemType.Tween)
                {
                    list.AddRange(item.twMember.GetTweensByIntId(p_intId));
                }
            }
            return list;
        }

        public override List<object> GetTweenTargets()
        {
            if (this.items == null)
            {
                return null;
            }
            List<object> list = new List<object>();
            int count = this.items.Count;
            for (int i = 0; i < count; i++)
            {
                HOTSeqItem item = this.items[i];
                if (item.seqItemType == SeqItemType.Tween)
                {
                    list.AddRange(item.twMember.GetTweenTargets());
                }
            }
            return list;
        }

        protected override bool GoTo(float p_time, bool p_play, bool p_forceUpdate, bool p_ignoreCallbacks)
        {
            if (!base._enabled)
            {
                return false;
            }
            if (p_time > base._fullDuration)
            {
                p_time = base._fullDuration;
            }
            else if (p_time < 0f)
            {
                p_time = 0f;
            }
            if ((base._fullElapsed == p_time) && !p_forceUpdate)
            {
                if (!base._isComplete && p_play)
                {
                    this.Play();
                }
                return base._isComplete;
            }
            base._fullElapsed = p_time;
            this.Update(0f, true, false, p_ignoreCallbacks);
            if (!base._isComplete && p_play)
            {
                this.Play();
            }
            return base._isComplete;
        }

        public float Insert(float p_time, IHOTweenComponent p_twMember)
        {
            return this.Insert(p_time, p_twMember, 0f);
        }

        private float Insert(float p_time, IHOTweenComponent p_twMember, float p_duration)
        {
            if (p_twMember != null)
            {
                Holoville.HOTween.HOTween.RemoveFromTweens(p_twMember);
                ((ABSTweenComponent) p_twMember).contSequence = this;
                CheckSpeedBasedTween(p_twMember);
            }
            HOTSeqItem item = (p_twMember == null) ? new HOTSeqItem(p_time, p_duration) : new HOTSeqItem(p_time, p_twMember as ABSTweenComponent);
            if (this.items == null)
            {
                this.items = new List<HOTSeqItem> { item };
                base._duration = item.startTime + item.duration;
                base.SetFullDuration();
                base._isEmpty = false;
                return base._duration;
            }
            bool flag = false;
            int count = this.items.Count;
            for (int i = 0; i < count; i++)
            {
                if (this.items[i].startTime >= p_time)
                {
                    this.items.Insert(i, item);
                    flag = true;
                    break;
                }
            }
            if (!flag)
            {
                this.items.Add(item);
            }
            base._duration = Mathf.Max(item.startTime + item.duration, base._duration);
            base.SetFullDuration();
            base._isEmpty = false;
            return base._duration;
        }

        public void InsertCallback(float p_time, TweenDelegate.TweenCallback p_callback)
        {
            this.InsertCallback(p_time, p_callback, null, null);
        }

        public void InsertCallback(float p_time, TweenDelegate.TweenCallbackWParms p_callback, params object[] p_callbackParms)
        {
            this.InsertCallback(p_time, null, p_callback, p_callbackParms);
        }

        private void InsertCallback(float p_time, TweenDelegate.TweenCallback p_callback, TweenDelegate.TweenCallbackWParms p_callbackWParms, params object[] p_callbackParms)
        {
            this.hasCallbacks = true;
            HOTSeqItem item = new HOTSeqItem(p_time, p_callback, p_callbackWParms, p_callbackParms);
            if (this.items == null)
            {
                this.items = new List<HOTSeqItem> { item };
            }
            else
            {
                bool flag = false;
                int count = this.items.Count;
                for (int i = 0; i < count; i++)
                {
                    if (this.items[i].startTime >= p_time)
                    {
                        this.items.Insert(i, item);
                        flag = true;
                        break;
                    }
                }
                if (!flag)
                {
                    this.items.Add(item);
                }
            }
            base._isEmpty = false;
        }

        public void InsertCallback(float p_time, GameObject p_sendMessageTarget, string p_methodName, object p_value, SendMessageOptions p_options = 0)
        {
            TweenDelegate.TweenCallbackWParms parms = new TweenDelegate.TweenCallbackWParms(Holoville.HOTween.HOTween.DoSendMessage);
            object[] objArray = new object[] { p_sendMessageTarget, p_methodName, p_value, p_options };
            this.InsertCallback(p_time, null, parms, objArray);
        }

        public override bool IsLinkedTo(object p_target)
        {
            if (this.items != null)
            {
                int count = this.items.Count;
                for (int i = 0; i < count; i++)
                {
                    HOTSeqItem item = this.items[i];
                    if ((item.seqItemType == SeqItemType.Tween) && item.twMember.IsLinkedTo(p_target))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public override bool IsTweening(int p_id)
        {
            if (base._enabled && (this.items != null))
            {
                int count = this.items.Count;
                for (int i = 0; i < count; i++)
                {
                    HOTSeqItem item = this.items[i];
                    if ((item.seqItemType == SeqItemType.Tween) && item.twMember.IsTweening(p_id))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public override bool IsTweening(object p_target)
        {
            if (base._enabled && (this.items != null))
            {
                int count = this.items.Count;
                for (int i = 0; i < count; i++)
                {
                    HOTSeqItem item = this.items[i];
                    if ((item.seqItemType == SeqItemType.Tween) && item.twMember.IsTweening(p_target))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public override bool IsTweening(string p_id)
        {
            if (base._enabled && (this.items != null))
            {
                int count = this.items.Count;
                for (int i = 0; i < count; i++)
                {
                    HOTSeqItem item = this.items[i];
                    if ((item.seqItemType == SeqItemType.Tween) && item.twMember.IsTweening(p_id))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        internal override void Kill(bool p_autoRemoveFromHOTween)
        {
            if (!base._destroyed)
            {
                if (this.items != null)
                {
                    int count = this.items.Count;
                    for (int i = 0; i < count; i++)
                    {
                        HOTSeqItem item = this.items[i];
                        if (item.seqItemType == SeqItemType.Tween)
                        {
                            item.twMember.Kill(false);
                        }
                    }
                    this.items = null;
                }
                base.Kill(p_autoRemoveFromHOTween);
            }
        }

        public float Prepend(IHOTweenComponent p_twMember)
        {
            return this.Prepend(p_twMember, 0f);
        }

        private float Prepend(IHOTweenComponent p_twMember, float p_duration)
        {
            if (this.items == null)
            {
                return this.Insert(0f, p_twMember);
            }
            if (p_twMember != null)
            {
                Holoville.HOTween.HOTween.RemoveFromTweens(p_twMember);
                ((ABSTweenComponent) p_twMember).contSequence = this;
                CheckSpeedBasedTween(p_twMember);
            }
            HOTSeqItem item = (p_twMember == null) ? new HOTSeqItem(0f, p_duration) : new HOTSeqItem(0f, p_twMember as ABSTweenComponent);
            float duration = item.duration;
            int count = this.items.Count;
            for (int i = 0; i < count; i++)
            {
                HOTSeqItem local1 = this.items[i];
                local1.startTime += duration;
            }
            this.items.Insert(0, item);
            base._duration += duration;
            base.SetFullDuration();
            base._isEmpty = false;
            return base._duration;
        }

        public float PrependInterval(float p_duration)
        {
            return this.Prepend(null, p_duration);
        }

        internal void Remove(ABSTweenComponent p_tween)
        {
            if (this.items != null)
            {
                int count = this.items.Count;
                for (int i = 0; i < count; i++)
                {
                    HOTSeqItem item = this.items[i];
                    if ((item.seqItemType == SeqItemType.Tween) && (item.twMember == p_tween))
                    {
                        this.items.RemoveAt(i);
                        break;
                    }
                }
                if (this.items.Count == 0)
                {
                    if (this.isSequenced)
                    {
                        base.contSequence.Remove(this);
                    }
                    this.Kill(!this.isSequenced);
                }
            }
        }

        public override void Restart()
        {
            if (base._fullElapsed == 0f)
            {
                this.PlayForward();
            }
            else
            {
                this.Rewind(true);
            }
        }

        public override void Rewind()
        {
            this.Rewind(false);
        }

        private void Rewind(bool p_play)
        {
            if (base._enabled && (this.items != null))
            {
                this.Startup();
                if (!base._hasStarted)
                {
                    this.OnStart();
                }
                base._isComplete = false;
                base._isLoopingBack = false;
                base._completedLoops = 0;
                base._fullElapsed = base._elapsed = 0f;
                int num = this.items.Count - 1;
                for (int i = num; i > -1; i--)
                {
                    HOTSeqItem item = this.items[i];
                    if (item.seqItemType == SeqItemType.Tween)
                    {
                        item.twMember.Rewind();
                    }
                }
                if (base._fullElapsed != base.prevFullElapsed)
                {
                    base.OnUpdate();
                    if (base._fullElapsed == 0f)
                    {
                        base.OnRewinded();
                    }
                }
                base.prevFullElapsed = base._fullElapsed;
                if (p_play)
                {
                    this.Play();
                }
                else
                {
                    this.Pause();
                }
            }
        }

        internal override void SetIncremental(int p_diffIncr)
        {
            int count = this.items.Count;
            for (int i = 0; i < count; i++)
            {
                HOTSeqItem item = this.items[i];
                if (item.seqItemType == SeqItemType.Tween)
                {
                    item.twMember.SetIncremental(p_diffIncr);
                }
            }
        }

        protected override void Startup()
        {
            if (!base.startupDone)
            {
                this.TweenStartupIteration();
                base.Startup();
            }
        }

        private void TweenStartupIteration()
        {
            HOTSeqItem item;
            bool flag = !this.steadyIgnoreCallbacks;
            if (flag)
            {
                this.steadyIgnoreCallbacks = true;
            }
            int count = this.items.Count;
            for (int i = 0; i < count; i++)
            {
                item = this.items[i];
                if (item.seqItemType == SeqItemType.Tween)
                {
                    item.twMember.Update(item.twMember.duration, true, true);
                }
            }
            for (int j = count - 1; j > -1; j--)
            {
                item = this.items[j];
                if (item.seqItemType == SeqItemType.Tween)
                {
                    item.twMember.Rewind();
                }
            }
            if (flag)
            {
                this.steadyIgnoreCallbacks = false;
            }
        }

        internal override bool Update(float p_shortElapsed, bool p_forceUpdate, bool p_isStartupIteration, bool p_ignoreCallbacks)
        {
            HOTSeqItem item;
            if (base._destroyed)
            {
                return true;
            }
            if (this.items == null)
            {
                return true;
            }
            if (!base._enabled)
            {
                return false;
            }
            if ((base._isComplete && !base._isReversed) && !p_forceUpdate)
            {
                return true;
            }
            if (((base._fullElapsed == 0f) && base._isReversed) && !p_forceUpdate)
            {
                return false;
            }
            if (base._isPaused && !p_forceUpdate)
            {
                return false;
            }
            base.ignoreCallbacks = p_isStartupIteration || p_ignoreCallbacks;
            if (!base._isReversed)
            {
                base._fullElapsed += p_shortElapsed;
                base._elapsed += p_shortElapsed;
            }
            else
            {
                base._fullElapsed -= p_shortElapsed;
                base._elapsed -= p_shortElapsed;
            }
            if (base._fullElapsed > base._fullDuration)
            {
                base._fullElapsed = base._fullDuration;
            }
            else if (base._fullElapsed < 0f)
            {
                base._fullElapsed = 0f;
            }
            this.Startup();
            if (!base._hasStarted)
            {
                this.OnStart();
            }
            bool flag = base._isComplete;
            bool flag2 = (!base._isReversed && !flag) && (base._elapsed >= base._duration);
            base.SetLoops();
            base.SetElapsed();
            base._isComplete = (!base._isReversed && (base._loops >= 0)) && (base._completedLoops >= base._loops);
            bool flag3 = !flag && base._isComplete;
            if (base._loopType == LoopType.Incremental)
            {
                if (this.prevIncrementalCompletedLoops != base._completedLoops)
                {
                    int num = base._completedLoops;
                    if ((base._loops != -1) && (num >= base._loops))
                    {
                        num--;
                    }
                    int num2 = num - this.prevIncrementalCompletedLoops;
                    if (num2 != 0)
                    {
                        this.SetIncremental(num2);
                        this.prevIncrementalCompletedLoops = num;
                    }
                }
            }
            else if (this.prevIncrementalCompletedLoops != 0)
            {
                this.SetIncremental(-this.prevIncrementalCompletedLoops);
                this.prevIncrementalCompletedLoops = 0;
            }
            int count = this.items.Count;
            if (this.hasCallbacks && !base._isPaused)
            {
                List<HOTSeqItem> list = null;
                for (int i = 0; i < count; i++)
                {
                    item = this.items[i];
                    if (item.seqItemType == SeqItemType.Callback)
                    {
                        bool flag4;
                        bool flag5 = base.prevCompletedLoops != base._completedLoops;
                        bool flag6 = ((base._loopType == LoopType.Yoyo) || (base._loopType == LoopType.YoyoInverse)) && ((base._isLoopingBack && !flag5) || (flag5 && !base._isLoopingBack));
                        float num5 = !base._isLoopingBack ? base._elapsed : (base._duration - base._elapsed);
                        float num6 = !base._isLoopingBack ? this.prevElapsed : (base._duration - this.prevElapsed);
                        if (base._isLoopingBack)
                        {
                            flag4 = ((flag6 && ((item.startTime >= num5) || (base._completedLoops != base.prevCompletedLoops))) && (item.startTime <= num6)) || ((item.startTime >= num5) && ((!base._isComplete && (base._completedLoops != base.prevCompletedLoops)) || (item.startTime <= num6)));
                        }
                        else
                        {
                            flag4 = ((!flag6 && ((item.startTime <= num5) || (base._completedLoops != base.prevCompletedLoops))) && (item.startTime >= num6)) || ((item.startTime <= num5) && ((!base._isComplete && (base._completedLoops != base.prevCompletedLoops)) || (item.startTime >= num6)));
                        }
                        if (flag4)
                        {
                            if (list == null)
                            {
                                list = new List<HOTSeqItem>();
                            }
                            if (item.startTime > num5)
                            {
                                list.Insert(0, item);
                            }
                            else
                            {
                                list.Add(item);
                            }
                        }
                    }
                }
                if (list != null)
                {
                    foreach (HOTSeqItem item2 in list)
                    {
                        if (item2.callback != null)
                        {
                            item2.callback();
                        }
                        else if (item2.callbackWParms != null)
                        {
                            item2.callbackWParms(new TweenEvent(this, item2.callbackParms));
                        }
                    }
                }
            }
            if (base._duration > 0f)
            {
                float num7 = base._isLoopingBack ? (base._duration - base._elapsed) : base._elapsed;
                for (int j = count - 1; j > -1; j--)
                {
                    item = this.items[j];
                    if ((item.seqItemType == SeqItemType.Tween) && (item.startTime > num7))
                    {
                        if (item.twMember.duration > 0f)
                        {
                            item.twMember.GoTo(num7 - item.startTime, p_forceUpdate, true);
                        }
                        else
                        {
                            item.twMember.Rewind();
                        }
                    }
                }
                for (int k = 0; k < count; k++)
                {
                    item = this.items[k];
                    if ((item.seqItemType == SeqItemType.Tween) && (item.startTime <= num7))
                    {
                        if (item.twMember.duration > 0f)
                        {
                            item.twMember.GoTo(num7 - item.startTime, p_forceUpdate);
                        }
                        else
                        {
                            item.twMember.Complete();
                        }
                    }
                }
            }
            else
            {
                for (int m = count - 1; m > -1; m--)
                {
                    item = this.items[m];
                    if (item.seqItemType == SeqItemType.Tween)
                    {
                        item.twMember.Complete();
                    }
                }
                if (!flag)
                {
                    flag3 = true;
                }
            }
            if (base._fullElapsed != base.prevFullElapsed)
            {
                base.OnUpdate();
                if (base._fullElapsed == 0f)
                {
                    if (!base._isPaused)
                    {
                        base._isPaused = true;
                        base.OnPause();
                    }
                    base.OnRewinded();
                }
            }
            if (flag3)
            {
                if (!base._isPaused)
                {
                    base._isPaused = true;
                    base.OnPause();
                }
                base.OnComplete();
            }
            else if (flag2)
            {
                base.OnStepComplete();
            }
            base.ignoreCallbacks = false;
            this.prevElapsed = base._elapsed;
            base.prevFullElapsed = base._fullElapsed;
            base.prevCompletedLoops = base._completedLoops;
            return flag3;
        }

        internal override bool steadyIgnoreCallbacks
        {
            get
            {
                return base._steadyIgnoreCallbacks;
            }
            set
            {
                base._steadyIgnoreCallbacks = value;
                if (this.items != null)
                {
                    int count = this.items.Count;
                    for (int i = 0; i < count; i++)
                    {
                        HOTSeqItem item = this.items[i];
                        if (item.twMember != null)
                        {
                            item.twMember.steadyIgnoreCallbacks = value;
                        }
                    }
                }
            }
        }

        private class HOTSeqItem
        {
            private readonly float _duration;
            public readonly TweenDelegate.TweenCallback callback;
            public readonly object[] callbackParms;
            public readonly TweenDelegate.TweenCallbackWParms callbackWParms;
            public readonly Sequence.SeqItemType seqItemType;
            public float startTime;
            public readonly ABSTweenComponent twMember;

            public HOTSeqItem(float p_startTime, ABSTweenComponent p_twMember)
            {
                this.startTime = p_startTime;
                this.twMember = p_twMember;
                this.twMember.autoKillOnComplete = false;
                this.seqItemType = Sequence.SeqItemType.Tween;
            }

            public HOTSeqItem(float p_startTime, float p_duration)
            {
                this.seqItemType = Sequence.SeqItemType.Interval;
                this.startTime = p_startTime;
                this._duration = p_duration;
            }

            public HOTSeqItem(float p_startTime, TweenDelegate.TweenCallback p_callback, TweenDelegate.TweenCallbackWParms p_callbackWParms, params object[] p_callbackParms)
            {
                this.seqItemType = Sequence.SeqItemType.Callback;
                this.startTime = p_startTime;
                this.callback = p_callback;
                this.callbackWParms = p_callbackWParms;
                this.callbackParms = p_callbackParms;
            }

            public float duration
            {
                get
                {
                    if (this.twMember == null)
                    {
                        return this._duration;
                    }
                    return this.twMember.duration;
                }
            }
        }

        private enum SeqItemType
        {
            Interval,
            Tween,
            Callback
        }
    }
}

